<?php

namespace app\service;

use app\model\Room;
use app\model\RoomUser;
use app\model\AccountingRecord;
use app\model\User;
use app\controller\AccountingController;
use Carbon\Carbon;

class AutoSettlementService
{
    private static $instance = null;
    
    private function __construct()
    {
    }
    
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * 检查并处理需要自动结算的房间
     */
    public function processAutoSettlement()
    {
        try {
            $inactiveRooms = $this->getInactiveRooms();
            
            if (empty($inactiveRooms)) {
                error_log('没有需要自动结算的房间');
                return ['processed' => 0, 'rooms' => []];
            }
            
            $processedRooms = [];
            
            foreach ($inactiveRooms as $room) {
                try {
                    $result = $this->autoSettleRoom($room);
                    $processedRooms[] = $result;
                    error_log("房间自动结算完成: room_id={$room->id}, result=" . json_encode($result));
                } catch (\Exception $e) {
                    error_log("房间自动结算失败: room_id={$room->id}, error=" . $e->getMessage());
                    $processedRooms[] = [
                        'room_id' => $room->id,
                        'room_code' => $room->room_code,
                        'success' => false,
                        'error' => $e->getMessage()
                    ];
                }
            }
            
            return [
                'processed' => count($processedRooms),
                'rooms' => $processedRooms
            ];
            
        } catch (\Exception $e) {
            error_log('自动结算处理失败: ' . $e->getMessage());
            return ['processed' => 0, 'rooms' => [], 'error' => $e->getMessage()];
        }
    }
    
    /**
     * 获取需要自动结算的房间（基于截止时间）
     */
    private function getInactiveRooms()
    {
        $now = Carbon::now();
        
        return Room::where('is_settled', 0)
            ->where('auto_settlement_at', '<=', $now)
            ->get();
    }
    
    /**
     * 获取需要发送结算通知的房间（5分钟后即将结算）
     */
    public function getRoomsNeedingNotification()
    {
        $fiveMinutesFromNow = Carbon::now()->addMinutes(5);
        $now = Carbon::now();
        
        return Room::where('is_settled', 0)
            ->where('settlement_notification_sent', 0)
            ->where('auto_settlement_at', '>', $now)
            ->where('auto_settlement_at', '<=', $fiveMinutesFromNow)
            ->get();
    }
    
    /**
     * 自动结算房间
     */
    private function autoSettleRoom($room)
    {
        try {
            // 检查房间是否有交易记录
            $hasRecords = AccountingRecord::where('room_id', $room->id)->exists();
            
            if (!$hasRecords) {
                // 没有交易记录，直接标记为已结算
                $room->status = 'finished';
                $room->auto_settled = 1; // 标记为自动结算
                $room->settlement_reason = '无交易记录，自动结算';
                $room->save();
                
                return [
                    'room_id' => $room->id,
                    'room_code' => $room->room_code,
                    'success' => true,
                    'reason' => '无交易记录',
                    'settlement_type' => 'auto'
                ];
            }
            
            // 有交易记录，执行正常结算流程
            $settlementData = $this->calculateRoomSettlement($room->id);
            
            if (empty($settlementData)) {
                // 没有有效的结算数据
                $room->status = 'finished';
                $room->auto_settled = 1;
                $room->settlement_reason = '无有效交易数据，自动结算';
                $room->save();
                
                return [
                    'room_id' => $room->id,
                    'room_code' => $room->room_code,
                    'success' => true,
                    'reason' => '无有效交易数据',
                    'settlement_type' => 'auto'
                ];
            }
            
            // 执行自动结算
            $this->executeAutoSettlement($room->id, $settlementData);
            
            return [
                'room_id' => $room->id,
                'room_code' => $room->room_code,
                'success' => true,
                'reason' => '自动结算完成',
                'settlement_type' => 'auto',
                'users_updated' => count($settlementData)
            ];
            
        } catch (\Exception $e) {
            error_log("自动结算房间失败: room_id={$room->id}, error=" . $e->getMessage());
            throw $e;
        }
    }
    
    /**
     * 计算房间结算数据
     */
    private function calculateRoomSettlement($roomId)
    {
        $roomUsers = RoomUser::where('room_id', $roomId)
            ->where('status', RoomUser::STATUS_ACTIVE)
            ->with('user')
            ->get();
        
        if ($roomUsers->isEmpty()) {
            return [];
        }
        
        $settlementData = [];
        
        foreach ($roomUsers as $roomUser) {
            $userId = $roomUser->user_id;
            $userName = $roomUser->user->nickname ?? '未知用户';
            
            // 获取该用户的所有记录
            $records = AccountingRecord::where('room_id', $roomId)
                ->where(function($query) use ($userId) {
                    $query->where('user_id', $userId)
                          ->orWhere('target_user_id', $userId);
                })
                ->get();
            
            $userTotal = 0;
            $payments = [];
            
            foreach ($records as $record) {
                if ($record->user_id == $userId) {
                    // 用户主动记分给他人
                    $userTotal += $record->score;
                } elseif ($record->target_user_id == $userId) {
                    // 他人记分给用户
                    $userTotal -= $record->score;
                }
            }
            
            if ($userTotal != 0 || !empty($payments)) {
                $settlementData[] = [
                    'user_id' => $userId,
                    'user_name' => $userName,
                    'total_score' => $userTotal,
                    'payments' => $payments
                ];
            }
        }
        
        return $settlementData;
    }
    
    /**
     * 执行自动结算
     */
    private function executeAutoSettlement($roomId, $settlementData)
    {
        // 使用数据库事务确保结算的原子性
        \Illuminate\Database\Capsule\Manager::transaction(function () use ($roomId, $settlementData) {
            // 更新用户总分数
            $this->updateUsersTotalScore($settlementData);
            
            // 标记房间为已结算
            $this->markRoomAsSettled($roomId, true);
            
            // 标记所有相关记录为已结算
            $this->markRecordsAsSettled($roomId);
        });
    }
    
    /**
     * 更新用户总分数
     */
    private function updateUsersTotalScore($settlementData)
    {
        foreach ($settlementData as $userSettlement) {
            $userId = $userSettlement['user_id'];
            $totalScore = $userSettlement['total_score'];
            
            if ($totalScore != 0) {
                $user = User::find($userId);
                if ($user) {
                    $user->updateTotalScore($totalScore);
                    error_log("自动结算更新用户总分数: user_id={$userId}, score_change={$totalScore}, new_total_score={$user->total_score}");
                }
            }
        }
    }
    
    /**
     * 标记房间为已结算
     */
    private function markRoomAsSettled($roomId, $isAuto = false)
    {
        $room = Room::find($roomId);
        if ($room) {
            // 强制所有房间用户状态更新为已结算
            RoomUser::where('room_id', $roomId)
                ->whereIn('status', [RoomUser::STATUS_ACTIVE, RoomUser::STATUS_LEFT])
                ->update([
                    'status' => RoomUser::STATUS_FINISHED,
                    'left_at' => Carbon::now()
                ]);
            
            $room->status = 'finished'; // 更新房间状态为已结算
            $room->current_players = 0; // 结算后房间人数为0
            if ($isAuto) {
                $room->auto_settled = 1;
                $room->settlement_reason = '2小时无动静，自动结算';
            }
            $room->save();
            
            // 创建房间结算汇总记录
            try {
                $settlementReason = $isAuto ? '自动结算（2小时无动静）' : '手动结算';
                \app\model\RoomSettlement::createSettlement($roomId, $isAuto ? 'auto' : 'manual', $settlementReason);
                error_log("房间结算汇总记录创建成功: room_id={$roomId}");
            } catch (\Exception $settlementException) {
                error_log('创建房间结算汇总记录失败: ' . $settlementException->getMessage());
                // 汇总记录创建失败不影响主要功能
            }
            
            error_log("房间已标记为结算: room_id={$roomId}, auto={$isAuto}, 所有用户已强制离开");
        }
    }
    
    /**
     * 标记所有相关记录为已结算
     */
    private function markRecordsAsSettled($roomId)
    {
        $updatedCount = AccountingRecord::where('room_id', $roomId)
            ->where('is_settled', 0)
            ->update(['is_settled' => 1]);
        
        error_log("标记记录为已结算: room_id={$roomId}, updated_count={$updatedCount}");
        return $updatedCount;
    }
    
    /**
     * 发送结算通知
     */
    public function sendSettlementNotifications()
    {
        try {
            $rooms = $this->getRoomsNeedingNotification();
            
            if (empty($rooms)) {
                error_log('没有需要发送结算通知的房间');
                return ['sent' => 0, 'rooms' => []];
            }
            
            $sentNotifications = [];
            
            foreach ($rooms as $room) {
                try {
                    $this->sendRoomSettlementNotification($room);
                    $sentNotifications[] = [
                        'room_id' => $room->id,
                        'room_code' => $room->room_code,
                        'settlement_at' => $room->auto_settlement_at->format('Y-m-d H:i:s')
                    ];
                    error_log("结算通知已发送: room_id={$room->id}");
                } catch (\Exception $e) {
                    error_log("发送结算通知失败: room_id={$room->id}, error=" . $e->getMessage());
                }
            }
            
            return [
                'sent' => count($sentNotifications),
                'rooms' => $sentNotifications
            ];
            
        } catch (\Exception $e) {
            error_log('发送结算通知失败: ' . $e->getMessage());
            return ['sent' => 0, 'rooms' => [], 'error' => $e->getMessage()];
        }
    }
    
    /**
     * 发送房间结算通知
     */
    private function sendRoomSettlementNotification($room)
    {
        try {
            // 计算剩余时间
            $remainingMinutes = Carbon::now()->diffInMinutes($room->auto_settlement_at, false);
            $remainingTime = $this->formatRemainingTime($remainingMinutes);
            
            // 发送WebSocket通知
            $websocketService = \app\service\WebSocketService::getInstance();
            $websocketService->sendSettlementNotification($room->id, $remainingTime);
            
            // 标记通知已发送
            $room->settlement_notification_sent = 1;
            $room->save();
            
        } catch (\Exception $e) {
            error_log("发送房间结算通知失败: room_id={$room->id}, error=" . $e->getMessage());
            throw $e;
        }
    }
    
    /**
     * 格式化剩余时间
     */
    private function formatRemainingTime($minutes)
    {
        if ($minutes <= 0) {
            return '即将结算';
        } elseif ($minutes < 60) {
            return "还有{$minutes}分钟自动结算";
        } else {
            $hours = floor($minutes / 60);
            $mins = $minutes % 60;
            return "还有{$hours}小时{$mins}分钟自动结算";
        }
    }
}
